#  Copyright (c) 2023. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
#  Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
#  Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
#  Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
#  Vestibulum commodo. Ut rhoncus gravida arcu.

# coding:utf8
from PyQt5.QtGui import QColor


def _get_range_ips(start: str, end: str):
    start_ = IP(start)
    end_ = IP(end)
    range_ = range(int(start_.tail()), int(end_.tail()) + 1)
    front = start_.header_3()
    return [front + '.' + str(tail) for tail in range_]


class IP(object):
    def __init__(self, ip):
        """ """
        if isinstance(ip, IP):
            self.__dict__ = ip.__dict__
        else:
            if self.check_ip_formatter(ip):
                self._ip = ip
            else:
                raise TypeError("不是一个IP")
                
    @property
    def ip(self):
        return self._ip

    @staticmethod
    def check_ip_formatter(ip: str):
        import re

        if not isinstance(ip, str):
            return None
            # raise TypeError("IP 必须是字符串类型")

        match = re.match(r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$', ip)
        if not match:
            return None
        
        ip_int_list = [int(d) for d in ip.split('.')]
        for d in ip_int_list:
            if not 0 <= d <= 255:
                return None
        return True

    def header_3(self):
        list_secs = self.list_4_section()
        list_secs.pop()
        return '.'.join(list_secs)

    def next_ip(self, n=1) -> str:
        int_tail = int(self.tail()) + n
        if int_tail > 255:
            raise ValueError("IP值超过范围")
        return self.replace_tail(int_tail)

    def last_ip(self, n=2):
        int_tail = int(self.tail()) - n
        if int_tail <= 0:
            raise ValueError("IP值超过范围")
        return self.replace_tail(int_tail)

    def tail(self):
        """ """
        list_section = self.list_4_section()
        return list_section[-1]

    def section(self):
        list_section = self.list_4_section()
        return list_section[-2]

    def hope_grateway(self):
        list_secs = self.list_4_section()
        list_secs.pop()
        list_secs.append('1')
        return '.'.join(list_secs)

    def list_4_section(self):
        return self._ip.split('.')

    @staticmethod
    def join_4_section(ip_sections) -> str:
        return '.'.join(ip_sections)
    
    @classmethod
    def generate_ip_obj(cls, ip_section_tuple: tuple):
        ipstr = cls.join_4_section(ip_section_tuple)
        return cls(ipstr)
        

    def replace_section(self, section: [int, str]):
        """
        生成一个替换掉字段的IP
        返回一个ip字符串
        """
        int_sec = int(section)
        if int_sec >= 0 and int_sec <= 255:
            str_sec = str(int_sec)
            lit = self.list_4_section()
            lit[2] = str_sec
            return self.join_4_section(lit)
        else:
            raise ValueError("ip_sections 字段不在正确的范围")

    def replace_tail(self, tail: [int, str])->str:
        """
        生成一个替换掉尾部的IP
        返回一个ip字符串
        """
        int_tail = int(tail)
        if int_tail >= 0 and int_tail <= 255:
            str_tail = str(int_tail)
            lit = self.list_4_section()
            lit[-1] = str_tail
            return self.join_4_section(lit)
        else:
            raise ValueError("ip_sections 字段不在正确的范围")

    def generate_2_254_ips(self):
        """
        生成同字段的Ip列表, 范围为2到254
        返回一个IP生成器
        :return
            generator 生成器

        """
        for num in range(2, 255):
            yield self.replace_tail(num)
            
    

    def is_equal_section(self, ip):
        return IP(ip).section() == self.section()

    def __lt__(self, other):
        """
        <
        """
        if self.is_equal_section(other):
            # 字段相同
            return int(self.tail()) < int(other.tail())
        else:
            # 比较字段
            return int(self.section()) < int(other.section())
        
    def __gt__(self, other):
        return not self < other
    
    @staticmethod
    def get_range_ipstr_list(ip1: str, ip2:str):
        
        ipo1 = IP(ip1)
        ipo2 = IP(ip2)
        
        if ipo1.section() != ipo2.section():
            raise ValueError("ip1 and ip2 section not equal")
        
        
        if ipo1 > ipo2:
            ipo1, ipo2 = ipo2, ipo1
            
        ipstr_list = []
        for tail in range(int(ipo1.tail()), int(ipo2.tail())+1):
            newip = ipo1.replace_tail(str(tail))
            ipstr_list.append(newip)
        return ipstr_list
        
        
    def __str__(self):
        return self.ip

    def is_ip_equal(self, other):
        """
        ==
        """
        return True if self.ip == other.ip else False


# STATE_UN_KNOW = 0
# STATE_FINDED = 1
# STATE_ON_LINE = 2
# STATE_NEW_ADD = 3


class IpState(IP):
    STATE_UN_KNOW = 0  # 背景白色
    STATE_INVALID = 1  # 灰色
    STATE_EXISTS = 2  # 蓝色
    STATE_NEW_ADD = 3  # 绿色
    
    def __init__(self, ip, state=0):
        """ """
        super(IpState, self).__init__(ip)

        self.state = state
        self.name = ""  # IP 对应的拥有者
        
    def is_online(self):
        return True if self.state in (IpState.STATE_NEW_ADD, IpState.STATE_EXISTS) else False

    def get_name(self):
        return self.name

    def get_color(self):
        if self.state == self.STATE_UN_KNOW:
            return QColor(255, 255, 255)
        elif self.state == self.STATE_INVALID:
            return QColor(170, 170, 170)
        elif self.state == self.STATE_EXISTS:
            return QColor(22, 150, 209)
        elif self.state == self.STATE_NEW_ADD:
            return QColor(29, 140, 29)

    def update_state(self):
        if self.state == self.STATE_UN_KNOW:
            # self.state = self.STATE_NEW_ADD
            return
        
        if self.state == self.STATE_INVALID:
            self.state = self.STATE_EXISTS
            return
        
        if self.state == self.STATE_EXISTS:
            # self.state = self.STATE_INVALID
            return
        
        if self.state == self.STATE_NEW_ADD:
            self.state = self.STATE_EXISTS
            return

    def set_unknow(self):
        self.state = self.STATE_UN_KNOW
    
    def set_exists(self):
        self.state = self.STATE_EXISTS

    def set_new(self):
        self.state = self.STATE_NEW_ADD
    
    def set_invalid(self):
        self.state = self.STATE_INVALID
        
    def set_state(self, state):
        self.state = state % 4

    def __str__(self):
        return f"<IpState: {self._ip}"
    
    
    @staticmethod
    def get_range_ipos(start:str, end:str):
        """
        :var
            start: ipstr
            end: ipstr
            
        :return
            [ ipo... ]
            or None
        """
        if IpState.check_ip_formatter(end) is None:
            # 将只选取start ip, 单一的IP
            end = None
        
        else:
            end = IpState(end)
            end.set_unknow()
            
        if IpState.check_ip_formatter(start) is None:
            start = None
        else:
            start = IpState(start)
            start.set_unknow()
            
        ipos_will_add = []
        #
        if start is None and end is None: return
        
        if start  and end is None:
            ipos_will_add.append(start)
            
        elif start is None and end:
            ipos_will_add.append(end)
        
        else :
            start_tail_int = int(start.tail())
            end_tail_int = int(end.tail())
            
            if start.header_3() != end.header_3():
                # 两个IP的前面三部分不一样
                # 必须放在add_ip_update_all_model上面
                
                ipos_will_add.append(start)
                ipos_will_add.append(end)

            elif start < end:
                for tail in range(start_tail_int, end_tail_int+1):
                    new_ip_str = start.replace_tail(tail)
                    new_ip_obj = IpState(new_ip_str)
                    new_ip_obj.set_unknow()
                    ipos_will_add.append(new_ip_obj)

            else:
                for tail in range(end_tail_int, start_tail_int+1):
                    new_ip_str = start.replace_tail(tail)
                    new_ip_obj = IpState(new_ip_str)
                    new_ip_obj.set_unknow()
                    ipos_will_add.append(new_ip_obj)
                    
            # todo if start == end, will add start and end ?
        
        return ipos_will_add
                    
